/**
 * 
 */
package com.feib.stms.batch.job;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Service;

import com.feib.stms.batch.domain.DeliveryPaymentChkSum;
import com.feib.stms.batch.service.DeliveryPaymentChkSumService;
import com.feib.stms.batch.service.MQService;

/**
 * @author Jimmy Liu
 *
 */
@Service("testMQJob")
public class TestMQJob {
	
    public final static Logger logger = LoggerFactory.getLogger(TestMQJob.class);

    public static final SimpleDateFormat BASIC_DATE_TIME_FORMAT = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
    
    private static ApplicationContext SPRING_CTX = null;
    
    /**
     * 驗資正常待碼
     */
    private static final String RT_OK = "P011";

    @Resource(name="mqService")
    private MQService mqService;
    
    @Resource(name="deliveryPaymentChkSumService")
    private DeliveryPaymentChkSumService deliveryPaymentChkSumService;
    
    /**
     * 一次抓取驗資檔案明細最多筆數(避免一次抓取過大的明細，影響效能)
     */
    private int maxRecords = 300;
    
    /**
     * 第1次驗資: true<br/>
     * 第2次驗資: false<br/>
     * 由Main主程式設定第一次驗資或是第二次驗資
     */
    private boolean firstTime = true;

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		SPRING_CTX = new ClassPathXmlApplicationContext(
                new String[] {"applicationContext-config.xml",	"applicationContext-dao.xml", "applicationContext-properties.xml"});
		

        Date start = new Date();
        logger.info("[開始] XXXXXXXXX  - {}", BASIC_DATE_TIME_FORMAT.format(start));
        
        try 
        {
        	TestMQJob job = (TestMQJob)SPRING_CTX.getBean("testMQJob");
        	
        	// 第一個參數 >0 時代表 第2次驗資
        	if (0 != args.length){
        		try 
        		{
        			if (0 < Integer.parseInt(args[0]))
        				job.setFirstTime(false); // 第2次驗資
        				job.execute();
				}
        		catch (Exception e)
        		{
        			logger.error(e.getMessage(), e);
        			throw new RuntimeException("invalide frist argument, must be 0 or 1");
				}
            }
        	
		}
        catch (Exception e)
        {
            logger.error(e.getMessage(), e);
		}
        finally
        {
            Date end = new Date();
            logger.info("[結束] XXXXXXXXXX  - ", BASIC_DATE_TIME_FORMAT.format(end));
            logger.info("共費時 - " + ((end.getTime() - start.getTime()) / 1000) + " 秒");
        	
        }

	}
	
	/**
	 * 執行批次
	 */
	public void execute()
	{
		
		Date SysDate=new  Date();
		logger.info("驗資即時電文銷帳系統時間：{}", SysDate);
		
		/* 取得下一工作日日期 */
		Date nextBussinessDay =deliveryPaymentChkSumService.getNextBusinessDay(SysDate);
	
        
        logger.info("取得下一工作日日期：{}", nextBussinessDay);
		
		/*取得尚未驗資資料  檔案 */
		//List<Long> filePks = getToDoUploadFile();
        
        List<Map<String, Object>>  chkUploadFiles  = deliveryPaymentChkSumService.queryToDoChkUploadFile(nextBussinessDay, firstTime);
        
		
		int toDoRecords = 0; // 檔案明細中，驗資尚未通過的總筆數
		
		for(Map<String, Object> chkUploadFile: chkUploadFiles)
		{
			int begIdx = 0;
			int endIdx = maxRecords - 1;
			Long uploadFilePk=(Long)chkUploadFile.get("UPLOAD_FILE_PK");
			logger.info("UPLOAD_FILE_PK：{}", uploadFilePk);
			
			// 逐個檔案處理，若檔案有問題，跳過繼續執行下一個
			try {
	
				toDoRecords = getAllToDoRecords(uploadFilePk); // 檔案明細中，驗資尚未通過的總筆數
				
				List<DeliveryPaymentChkSum> toDos = null;
				
				while(0 == toDoRecords && begIdx < toDoRecords) // TODO: 需測試一下回圈是否有問題
				{					
					toDos = getToDos(uploadFilePk, begIdx, endIdx);
					
					for(DeliveryPaymentChkSum toDo : toDos)
					{
						// 逐筆明細處理
						processSingleRecord(toDo);
						
					}
					
					// 設定下一次的開始跟結束
					begIdx = begIdx + maxRecords;
					endIdx = begIdx + maxRecords - 1;
					
					// free resource
					if (null != toDos)
						toDos.clear();
					toDos = null;
				}
				
				
			} catch (Exception e) {
				logger.error("驗資發生錯誤，請先排除問題，再修改驗資檔案(UPLOAD_FILE.UPLOAD_FILE_PK = {}) 的狀態後，重新執行", uploadFilePk);
			}
			finally
			{
				// TODO 更新資料庫 UPLOAD_FILE.fileStatus
			}
		}
		
		
		
		if (null != chkUploadFiles)
			chkUploadFiles.clear(); // free resource
		chkUploadFiles = null;
	}

	/**
	 * 
	 * @param deliveryPaymentChkSum
	 */
	private void processSingleRecord(DeliveryPaymentChkSum deliveryPaymentChkSum) {
		
		try
		{
			String rtChkMsgId = null; // 即時電文序號，若已存在，則使用原本的，否則產生一組新的
			String rtChkResult = null; // 即時電文回覆結果
			Date rtChkOutDate = new Date(); // 發送電文日期時間
			Date rtChkInDate = null; // 接收電文日期時間
			
			deliveryPaymentChkSum.getDealResultCode();
			
			if (this.firstTime)
			{
				// 第一次驗資
				rtChkMsgId = getNewMessageID();
				deliveryPaymentChkSum.setRtChkMsgId1(rtChkMsgId);
				
				deliveryPaymentChkSum.setRtChkOutDate1(rtChkOutDate);
			}
			else
			{
				// 第二次驗資
				rtChkMsgId = getNewMessageID();
				deliveryPaymentChkSum.setRtChkMsgId2(rtChkMsgId);

				deliveryPaymentChkSum.setRtChkOutDate2(rtChkOutDate);
			}
			
			// 組 送出去的電文 TITA
			String myTITA = genMqTita(deliveryPaymentChkSum, rtChkMsgId);
			
			logger.debug("");
			
			// 收到回傳電文
			String myTOTA = this.sendRequestToMQ(myTITA, rtChkMsgId);
			
			rtChkInDate = new Date();
			
			// 處理結果
			// TODO: 拆解結果
			rtChkResult = new String(myTOTA.substring(0, 0));
			deliveryPaymentChkSum.setDealResultCode(rtChkResult);
			if (this.firstTime)
			{
				deliveryPaymentChkSum.setRtChkResult1(rtChkResult);
				deliveryPaymentChkSum.setRtChkInDate1(rtChkInDate);
			}
			else
			{
				deliveryPaymentChkSum.setRtChkResult2(rtChkResult);
				deliveryPaymentChkSum.setRtChkInDate2(rtChkInDate);
			}
			
			if (RT_OK.equalsIgnoreCase(rtChkResult))
			{
				
			}
			else
			{
				// TODO: 需紀錄不足金額 (netAmount - lessAmount);				
				// deliveryPaymentChkSum.setLessAmount(lessAmount);
			}
					
			
		} 
		catch (Exception e) 
		{
			logger.error("驗資錯誤(processSingleRecord)", e);
		}
		finally
		{
			// TODO 將驗資結果更新至資料庫中			
		}
		
	}
	
	/**
	 * 產生MQ交易電文
	 * @param deliveryPaymentChkSum
	 * @return
	 */
	private String genMqTita(DeliveryPaymentChkSum deliveryPaymentChkSum, String rtChkMsgId) {
		StringBuffer result = new StringBuffer();
		
		
		// TODO 組電文
		
		
		return result.toString();
	}

	/**
	 * 取得待處理的明細
	 * @param filePk 驗資檔案PK
	 * @param begIdx 待處理紀錄 起始
	 * @param endIdx 待處理紀錄 結束
	 * @return
	 */
	private List<DeliveryPaymentChkSum> getToDos(Long filePk, int begIdx,
			int endIdx) {
		// TODO 
		return null;
	}

	/**
	 * 檔案明細中，驗資尚未通過的總筆數
	 * @param filePk 驗資檔PK
	 * @return
	 */
	private int getAllToDoRecords(Long filePk) {
		// TODO Auto-generated method stub
		return 0;
	}

	/**
	 * 跟資料庫取得尚未驗資檔案 PK<br/>
	 * <ol>
	 * <li> 讀取 UPLOAD_FILE 尚未驗資的檔案</li>
	 * <li> 更新 UPLOAD_FILE.fileStatus 驗資中，需依據第幾次驗資更新不同的代碼</li>
	 * </ol> 
	 * <ul>
	 * <li>當 fristTime = true，代表第1次驗資，抓取 UPLOAD_FILE.fileStatus = 0 的資料</li>
	 * <li>當 fristTime = false，代表第2次驗資，抓取 UPLOAD_FILE.fileStatus < 5( 0 ,1,3) 的資料</li>
	 * </ul>
	 * @return
	 */
	private List<Long> getToDoUploadFile()
	{
		// TODO: 讀取UPLOAD_FILE尚未驗資的檔案
		return null;
	}
	
	/**
	 * 產生新的電文序號<br/>
	 * @return
	 */
	private String getNewMessageID()
	{
		// TODO: 到資料庫讀取下一個MessageID
		return null;
	}
	
	/**
	 * 傳送電文
	 * @param myTITA 送出去電文
	 * @param myMessageID 電文序號
	 * @return 收到的電文
	 */
	private String sendRequestToMQ(String myTITA, String myMessageID)
	{
		logger.info("SendMQ starting...");
		
		logger.info("MQ TITA: {}, MessageID: {}", myTITA, myMessageID);
		
		// TODO: 紀錄發送電文於資料庫中
		
		String totaStr = null; //MQ 回傳的電文
		try {

	        if ("1".equals(MQService.MQonline))
	        {
	            /* MQ Online */ 
	            mqService.send(myTITA, MQService.MSG_TYPE_NONEXML, myMessageID, "");
	        }
	        else
	        {  
	            /* Fake MQ 模擬電文 */
	            mqService.send(myTITA, MQService.MSG_TYPE_NONEXML, myMessageID, "TOTA.txt");
	        }
	        
	        totaStr = mqService.rcv(myMessageID);
	        
	        logger.info("MQ TOTA: {}" + totaStr);
	        
		} catch (Exception e) {
			
            logger.error("[電文傳送錯誤]", e);
            
			totaStr = null;
		}
		finally
		{

			// TODO: 紀錄電文結果於資料庫中
		}
        
        return totaStr;
	}

	public void setFirstTime(boolean firstTime) {
		this.firstTime = firstTime;
	}

}
